﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.IO;

namespace BaseAddIn
{
    public static class Load
    {
        #region Public Methods

        public static void CarregaInstanciaRulesAddIn(string caminhoRules, ref List<Rules.BaseRuleAddIn> selectedRulesAddin, BaseAddIn.ProjectInfo.RuleFilesList ruleFilesList)
        {
            Assembly assemblyRule = null;
            List<FileInfo> files = null;
            Type[] tipos = null;
            ConstructorInfo construtor = null;             
            DirectoryInfo di = new DirectoryInfo(caminhoRules);
            Type tipoBaseRuleAddIn = typeof(Rules.BaseRuleAddIn);
            ProjectInfo.RuleList ruleList = ruleFilesList.FiltrarRules(tipoBaseRuleAddIn.FullName);
            ProjectInfo.Rule rule = null;

            if (selectedRulesAddin != null)
            {
                for (int i = selectedRulesAddin.Count - 1; i >= 0; i--)
                {
                    selectedRulesAddin[i].Dispose();
                }

                selectedRulesAddin.Clear();
            }

            selectedRulesAddin = new List<Rules.BaseRuleAddIn>();

            files = new List<FileInfo>(di.GetFiles("*Rules.dll", SearchOption.TopDirectoryOnly));
            files.Sort(SortFiles);

            foreach (FileInfo file in files)
            {
                assemblyRule = Assembly.LoadFrom(file.FullName);

                tipos = assemblyRule.GetExportedTypes();

                foreach (Type tipo in tipos)
                {
                    rule = ruleList.Contains(tipo.Name);

                    if (tipo.IsSubclassOf(tipoBaseRuleAddIn)
                        && rule != null
                        && rule.Enabled)
                    {
                        construtor = tipo.GetConstructor(Type.EmptyTypes);
                        selectedRulesAddin.Add((Rules.BaseRuleAddIn)construtor.Invoke(null));
                    }
                }
            }
        }

        public static void CarregaRules(string caminhoRules, ref ProjectInfo.RuleFilesList projeto)
        {
            Assembly assemblyRule = null;
            List<FileInfo> files = null;
            Type[] tipos = null;
            DirectoryInfo di = new DirectoryInfo(caminhoRules);
            Type tipoBaseFxCop = typeof(Rules.BaseRuleFXCop);
            Type tipoBaseRuleAddIn = typeof(Rules.BaseRuleAddIn);
            Type tipoDoubleClassAttribute = typeof(Rules.DoubleClassAttribute);
            object[] doubleRule;
            ProjectInfo.RuleFile ruleFile;
            ProjectInfo.Rule rule;

            if (projeto == null)
                projeto = new BaseAddIn.ProjectInfo.RuleFilesList();

            files = new List<FileInfo>(di.GetFiles("*Rules.dll", SearchOption.TopDirectoryOnly));
            files.Sort(SortFiles);

            foreach (FileInfo file in files)
            {
                assemblyRule = Assembly.LoadFrom(file.FullName);
                ruleFile = new ProjectInfo.RuleFile();
                ruleFile.Enabled = true;
                ruleFile.AllRulesEnabled = true;
                ruleFile.Name = file.FullName;
                ruleFile.Rules = new ProjectInfo.RuleList();

                tipos = assemblyRule.GetExportedTypes();

                foreach (Type tipo in tipos)
                {
                    if (tipo.IsSubclassOf(tipoBaseRuleAddIn)
                        || tipo.IsSubclassOf(tipoBaseFxCop))
                    {
                        rule = new ProjectInfo.Rule();
                        rule.Enabled = true;
                        rule.Name = tipo.Name;
                        rule.TipoRegra = tipo.BaseType.FullName;

                        doubleRule = tipo.GetCustomAttributes(tipoDoubleClassAttribute, false);
                        if(doubleRule.Length > 0)
                        {
                            rule.NameDoubleRule = ((Rules.DoubleClassAttribute)doubleRule[0]).NameOtherType;
                        }

                        ruleFile.Rules.Add(rule);
                    }
                }

                ruleFile.Rules.Sort(SortRule);
                projeto.Add(ruleFile);
            }
        }

        #endregion

        #region Private Methods

        private static int SortFiles(FileInfo file1, FileInfo file2)
        {
            return file1.Name.CompareTo(file2.Name);
        }

        private static int SortRule(ProjectInfo.Rule rule1, ProjectInfo.Rule rule2)
        {
            return rule1.Name.CompareTo(rule2.Name);
        }

        #endregion
    }
}
